<?php
    if (!defined('__IS_LEAF__')) exit('Access Denied!');
    
    /**
     * Dao层基类
     * 可用操作如：
     * 插入数据：$this->data()->insert()、$this->data=array(...)，$this->insert()
     * 更新数据：$this->username='xxx',$this->id=1,$this->update()或$this->where()->data()->update()
     * 删除数据：$this->delete(1,2,3)或$this->id=1;$this->delete()或$this->where('id in (1,2,3)')->delete()
     * 查询数据：$this->select(1,2,3)或$this->id=1;$this->select()或$this->where()->select();或$this->...find()等
     */
    class Dao extends Base{

        protected $_db;                     //数据库连接对象
        protected $_tableName;              //表名
        protected $_isNewRecord;            //此次操作是否要新增记录
        protected $_tableValid = true;      //表的存在性是否已被验证
        protected $_primaryKey;             //主键字段
        protected $_pk = '';                //主键
        public    $fields = '';            //字段列表，数组形式
        public    $where = '';             //where条件
        public    $limit = '';             //limit条件
        public    $order = '';             //order条件
        public    $data;                    //数据集
        protected $_values = '';            //curd数据时的隐式的值，如查询时，从where数组中择取的值
        protected $_executeData=false;       //
        protected $fieldsData = array();   //外部对属性赋值的数据数组，用于更新、插入、删除或查询
        private   $_dbStats='';              //数据库操作统计

        //实例化Dao模型
        public function __construct($tableName){
            if(!defined('__DB__STATS__')) define('__DB_STATS__', C('db_stats'));
            //获取表名
            $this->_tableName = $tableName;
            //初始化数据库操作统计
            if(__DB_STATS__) $this->_setDbStats();
            //执行Db数据库驱动类初始化
            $this->_initDb($this->_tableName);
            //设置通过查询数据库，dao的必须属性，如主键、字段等
            if($this->_primaryKey===null || $this->fields===null){
                //获取病设置对象的字段属性结构
                $this->_setTableStructure();
                //设置CURD之前的基本属性，如$this->order为主键递减
                $this->_setAttributes();
            }
        }

        /**
         * 初始化数据库操作统计
         * @param string $type 统计类型，curd的一种类型
         */
        final private function _setDbStats($type='', $time=''){
            if(empty($type)){
                $this->_dbStats=array(
                        'total' => array(
                                'run_time'  => 0,
                                'mem_usage' => 0,
                            ),
                        'select'=> array(),
                        'insert'=> array(),
                        'update' => array(),
                        'delete' => array(),
                    );
            }
        }

        /**
         * 返回MysqlPDO对象
         */
        private function _initDb($tableName){
            $db = DbFactory::getDbInstance($tableName);
            $this->_db = $this->_tableValid ? $db : false;
            if($this->_db === false) error($tableName.L('dao_error'));
        }

        /**
         * 获取表结构构成
         */
        private function _setTableStructure(){
            //获取表结构
            $tableStrucSql = "SHOW FULL FIELDS FROM {$this->_tableName}";
            try{
                $tableStructure = $this->_db->query($tableStrucSql);
            }catch(PDOException $e){
                $this->error($e->getMessage());
            }
            //获取字段集合和主键
            $fields = array();
            $primaryKey = '';
            foreach ($tableStructure as $key => $value) {
                //如果字段集合为null，则获取字段集合
                if($value['Key']==='PRI'){
                    $primaryKey = $value['Field'];
                }
                $fields[] = '`'.$value['Field'].'`';
            }
            $this->_primaryKey = $primaryKey;
            $this->fields = $fields;
        }

        private function _setAttributes(){
            $this->order();
        }

        /**
         * field字段选取
         */
        public function field($field=''){
            if (empty($field)) {
                $field = $this->fields;
            }elseif (is_array($field)) {
                # code...
            }elseif (is_string($field)) {
                
            }
            return $this;
        }

        /**
         * where条件
         * @param mixed $where 字符串或数组类型
         */
        final public function where($where=null){
            $whereArr = func_get_args();
            $res  =$this->parseWhere($whereArr);
            return $res;
        }

        /**
         * 解析where函数的条件
         */
        final private function parseWhere($whereArr){
            $count = count($whereArr);
            //如果$where条件为数组类型，则为where( array('id','>',1), array('address','=','朝阳') )等类型格式
            if( $count>0 && !is_string($whereArr[0]) ){
                $whereStr = ' where ';
                $executeData = array();
                foreach ($whereArr as $key => $value) {
                    //如果where条件循环value为“AND”或“OR”，则跳出循环
                    if(is_string($value)) continue;
                    //$type变量，用于判断是AND连接还是OR连接
                    $type = false;
                    if(isset($whereArr[$key+1]) && is_string($whereArr[$key+1])){
                        $type = strtoupper($whereArr[++$key]);
                    }else{
                        $type = 'AND';
                    }
                    //对between、in等做不同的处理
                    switch ($value[1]) {
                        //如果为between
                        case 'between':
                            $betweenValues  = explode(',', $value[2]);
                            $whereStr .= '`'.$value[0].'` '.BETWEEN.' :'.$value[0].$key.$betweenValues[0].' AND :'.$value[0].$key.$betweenValues[1].' '.$type.' ';
                            $executeData[':'.$value[0].$key.$betweenValues[0]] = $betweenValues[0];
                            $executeData[':'.$value[0].$key.$betweenValues[1]] = $betweenValues[1];
                            break;
                        //如果为in，in查询特殊，无法直接将 in (1,2,3)中“(1,2,3)”整体做绑定参数
                        case 'in':
                            $inValues = explode(',', $value[2]);
                            $executeData = array();
                            foreach ($inValues as $inKey => $inValue) {
                                $inParam .= ':in'.$inKey.',';
                                $executeData[':in'.$inKey] = $inValue;
                            }
                            $inParam = trim($inParam, ',');
                            $whereStr .= '`'.$value[0].'` IN ('.$inParam.') '.$type.' ';
                            break;
                        default:
                            $whereStr .= '`'.$value[0].'` '.$value[1].' :'.$value[0].$key.' '.$type.' ';
                            $executeData[':'.$value[0].$key] = $value[2];
                            break;
                    }
                }
            }else{
                $whereStr = ' where '.$whereArr[0];
            }
            //因为$whereStr是foreach之后拼接的，所以最后会多一个AND或OR，需要去除
            $this->where = trim($whereStr, $type.' ');
            $this->_executeData = $executeData;
            return $this;
        }

        /**
         * 待处理的数据集，适用于insert、update
         * @param array $data数据集合
         */
        public function data(array $data){
            //对数据集进行合法性过滤

        }

        public function limit($limit=''){
            if(empty($limit)){
                $limit = " limit 1 ";
            }elseif(is_string($limit)){
                $limit = ' limit '.$limit;
            }elseif(is_array($limit)) {
            }
            $this->limit = $limit;
            return $this;
        }

        public function order($order=null){
            if(is_null($order)){
                $order = "order by `{$this->_primaryKey}` desc";
            }
            $this->order = $order;
            return $this;
        }

        public function group($group=''){
            if(empty($group)){
            }
            return $this;
        }

        /**
         * 更新数据
         */
        public function update($update=null){
            if(is_null($update)){
                $res = $this->_db->update($this->_tableName, $this->_values);
            }
        }

        /**
         * 插入数据
         */
        public function insert(){
            $res = $this->_db->insert($this->_tableName, $this->fields, $this->_values);
        }

        public function delete($delte=null){
            $res = $this->_db->delete($thi->_tableName, $this->where);
        }

        /**
         * select查询数据
         */
        public function select(){
            $fields = implode(',', $this->fields);
            $table = $this->_tableName;
            $where = $this->where;
            $limit = $this->limit;
            $group = $this->group;
            $order = $this->order;
            $values = $this->_executeData;
            $res  = $this->_db->select($table, $fields, $where, $group, $order, $limit, $values);
            //如果开启了数据库信息统计，则执行统计信息添加操作
            if(__DB_STATS__){
                $sqlStats = $this->getLastQueryStat();
                $this->_dbStatsAdd('select', $sqlStats);
            }
            return $res;
        }

        /**
         * 如果开启了db_stats，此函数可悲调用，用于添加统计信息
         * @access private
         * @param string $type 添加类型，值为select、insert、update或delete
         * @param array $sqlStats 单条sql的统计信息
         */
        final private function _dbStatsAdd($type, $sqlStats){
            //如果开启了数据库信息统计，则进行统计操作
            if(__DB_STATS__){
                $this->_dbStats['total']['run_time']   += $sqlStats['run_time'];
                $this->_dbStats['total']['mem_usage']  += $sqlStats['mem_usage'];
                $this->_dbStats[$type]['run_time']  += $sqlStats['run_time'];
                $this->_dbStats[$type]['mem_usage'] += $sqlStats['mem_usage'];
                $this->_dbStats[$type]['detail'][] = $sqlStats;
            }
        }

        /**
         * 执行有结果集的查询
         */
        public function query($sql){
            return $this->_db->query($sql);
        }

        /**
         * 
         */
        private function _executeData(){

        }

        /**
         * 执行删除、增加或修改的查询
         */
        public function exec($sql){
            return $this->_db->exec($sql);
        }

        final public function getLastSql(){
            return $this->_db->getLastSql();
        }

        final public function getLastQueryStat(){
            return $this->_db->getLastQueryStat();
        }

        public function lastInsertId(){
            
        }

        /**
         * 获取当条结果集
         */
        public function find(){

        }

        /**
         * 获取当行记录中某一个字段的值
         */
        public function getField(){

        }

        /**
         * 获取当前Dao或Service的表名
         */
        public function getThisTable(){
            return $this->_tableName;
        }

        /**
         * 获取当前Dao或service的字段集合
         */
        public function getThisFields(){
            return $this->fields;
        }

        /**
         * 获取最近一次对数据库进行操作的信息，用于调试或统计及日志记录等
         */
        public function getLastQueryInfo(){

        }


        public function __set($call, $value){
            //转化值，将name转化为`name`类型
            $field = '`'.$call.'`';
            //如果外部设置的属性在字段列表，则进行属性赋值
            if(in_array($field, $this->fields)){
                $this->fieldsData[$field] = $value;
            }
        }

        public function __get($call)
        {
            parent::__get($call);
        }

        public function __destruct(){
            //如果开启了sql记录，则将数据库统计信息写入文件
            if(__DB_STATS__){
                Log::sqlLogRecord($this->_dbStats);
            }
            P($this->_dbStats);
        }

    }
